// 如何设计一个控制并发数的任务队列？
class ControllTask {
  constructor(list, limit, cb) {
    this.list = list;
    this.limit = limit;
    this.cb = cb;
    this.runIdx = 0;
    this.result = [];
    this.run();
  }

  add(task) {
    this.list.push(task);
    this.run();
  }

  run() {
    let len = this.list.length;
    while (this.limit && this.runIdx < len) {
      const task = this.list[this.runIdx++];
      if (task) {
        this.limit--;
        task()
          .then((res) => {
            console.log('res: ', res);
            this.result.push(res);
          })
          .finally(() => {
            this.limit++;
            if (this.list.indexOf(task) === len - 1) {
              this.cb(this.result);
            } else {
              this.run();
            }
          });
      }
    }
  }
}

const sleep = (wait) => new Promise((r) => setTimeout(r, wait));

const f1 = async () => {
  await sleep(2000);
  return Promise.resolve(0);
};

const f2 = async () => {
  await sleep(1000);
  return Promise.resolve(1);
};

const f3 = async () => {
  await sleep(1000);
  return Promise.resolve(2);
};

const f4 = async () => {
  await sleep(2000);
  return Promise.resolve(3);
};

const f5 = async () => {
  await sleep(3000);
  return Promise.resolve(4);
};

// const list = Array(5)
//   .fill(0)
//   .map((o, i) => () => Promise.resolve(i));
const list = [f1, f2, f3, f4];
const limit = 2;
const cb = (data) => {
  console.log('done', data);
};
const tasks = new ControllTask(list, limit, cb);
tasks.add(f5);
